type reg = string;;
type label = string;;
type imm = int;;  

(* Tipi per Commands*)
type asm_com =
    Halt
	| Nop
	| Add of reg * reg * reg
	| AddI of reg * imm * reg
	| Sub of reg * reg * reg
	| Mul of reg * reg * reg
	| Load of reg * reg * reg
	| Store of reg * reg * reg
	| Jump of label
	| Bne of reg * reg * label
	| Beq of reg * reg * label
	| Slt of reg * reg * reg
	(*| Jal of label*reg*reg*int (*scrive l'indirizzo di ritorno in $31 e salta a label*)  *)
	| JR (*salta all'indirizzo contenuto in $31*)
;;
 type asm_prog = ASM_Program of (label*asm_com) list;;

let asm_instr_to_string (label,com)= label^" : "^
						(match com with 
							 Halt -> "Halt;"
							| Nop -> "Nop;"
							| Add (r1,r2 ,r3) -> "Add "^r1^" "^r2^" "^r3^";"
							| AddI (r1,imm ,r3) -> "AddI "^r1^" "^string_of_int(imm)^" "^r3^";"
							| Sub(r1,r2 ,r3) -> "Sub "^r1^" "^r2^" "^r3^";"
							| Mul (r1,r2 ,r3) -> "Mul "^r1^" "^r2^" "^r3^";"
							| Load(r1,r2 ,r3) -> "Load "^r1^" "^r2^"["^r3^"];"
							| Store(r1,r2 ,r3) -> "Store "^r1^"["^r2^"] "^r3^";"
							| Jump(label)-> "Jump at "^label^";"
							| Bne (r1,r2,label) -> "If "^r1^"!="^r2^"then branch at "^label^";"
							| Beq (r1,r2,label) -> "If "^r1^"="^r2^" then branch at "^label^";"
							| Slt (r1,r2,r3) -> "if "^r2^"<"^r3^"set "^r1^"=1;"
							| JR -> "JR"
							)^"\n";;
 
let asm_program_to_string (ASM_Program(p)) = 
	let rec convert prog = (match prog with
	| head::tail -> asm_instr_to_string(head)^convert tail
	| _ -> ""
	)
	in convert p;;
																								
let salva_registri = [
																	("",Store("$sp","$0","$1"));
																	("",AddI("$sp",1,"$sp"));
																	("",Store("$sp","$0","$2"));
																	("",AddI("$sp",1,"$sp"));
																	("",Store("$sp","$0","$3"));
																	("",AddI("$sp",1,"$sp"));
																	("",Store("$sp","$0","$4"));
																	("",AddI("$sp",1,"$sp"));
																	("",Store("$sp","$0","$5"));
																	("",AddI("$sp",1,"$sp"));
																	("",Store("$sp","$0","$6"));
																	("",AddI("$sp",1,"$sp"));
																	("",Store("$sp","$0","$7"));
																	("",AddI("$sp",1,"$sp"));
																	("",Store("$sp","$0","$8"));
																	("",AddI("$sp",1,"$sp"));
																	("",Store("$sp","$0","$9"));
																	("",AddI("$sp",1,"$sp"));
																	("",Store("$sp","$0","$10"));
																	("",AddI("$sp",1,"$sp"));
																	("",Store("$sp","$0","$11"));
																	("",AddI("$sp",1,"$sp"));
																	("",Store("$sp","$0","$12"));
																	("",AddI("$sp",1,"$sp"));
																	("",Store("$sp","$0","$13"));
																	("",AddI("$sp",1,"$sp"));
																	("",Store("$sp","$0","$14"));
																	("",AddI("$sp",1,"$sp"));
																	("",Store("$sp","$0","$15"));
																	("",AddI("$sp",1,"$sp"));
																	("",Store("$sp","$0","$16"))
																	]
																	
let ripristina_registri = [
																					("",Load("$1","$sp","$0"));
																					("",AddI("$sp",1,"$sp"));
																					("",Load("$2","$sp","$0"));
																					("",AddI("$sp",1,"$sp"));
																					("",Load("$3","$sp","$0"));
																					("",AddI("$sp",1,"$sp"));
																					("",Load("$4","$sp","$0"));
																					("",AddI("$sp",1,"$sp"));
																					("",Load("$5","$sp","$0"));
																					("",AddI("$sp",1,"$sp"));
																					("",Load("$6","$sp","$0"));
																					("",AddI("$sp",1,"$sp"));
																					("",Load("$7","$sp","$0"));
																					("",AddI("$sp",1,"$sp"));
																					("",Load("$8","$sp","$0"));
																					("",AddI("$sp",1,"$sp"));
																					("",Load("$9","$sp","$0"));
																					("",AddI("$sp",1,"$sp"));
																					("",Load("$10","$sp","$0"));
																					("",AddI("$sp",1,"$sp"));
																					("",Load("$11","$sp","$0"));
																					("",AddI("$sp",1,"$sp"));
																					("",Load("$12","$sp","$0"));
																					("",AddI("$sp",1,"$sp"));
																					("",Load("$13","$sp","$0"));
																					("",AddI("$sp",1,"$sp"));
																					("",Load("$14","$sp","$0"));
																					("",AddI("$sp",1,"$sp"));
																					("",Load("$15","$sp","$0"));
																					("",AddI("$sp",1,"$sp"));
																					("",Load("$16","$sp","$0"))
																				]